#include <middleware/gm_api/skfapi.h>
#include <middleware/mk_lib/mk_auto_mutex.h>
#include <middleware/mk_lib/mk_utility.h>
#include <middleware/mk_lib/mk_logger.h>

#include <middleware/apdu/apdu.lib/apdu_lib_mac_mgr.h>
#include "gm_global.h"
#include "gm_defs.h"
#include "../gm_data_mgr/gm_sc_mgr.h"

ULONG DEVAPI SKF_MacInit (HANDLE hKey, BLOCKCIPHERPARAM* pMacParam, HANDLE *phMac)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_MacInit()");

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;

	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;
	gm_sc_mac *pmac	=NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	lRslt = app_mac_init(hdev, app_id, cont_id, pkey->key_id(), pkey->Algid(), 
					pMacParam->IV, pMacParam->IVLen,
					pMacParam->PaddingType, pMacParam->FeedBitLen);

	ERROR_THROW_APDU(lRslt)
	
	pmac = pCont->create_mac_key(pkey->key_id(), pkey->Algid());
	*phMac = pmac->get_handle();

END_OF_FUN:
	DBG_LOGMSG("leave SKF_MacInit(), ret=%08x", lRslt);
	return lRslt;
}
ULONG DEVAPI SKF_Mac(HANDLE hMac, BYTE* pbData, ULONG ulDataLen, BYTE *pbMacData, ULONG *pulMacLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_Mac(), ulDataLen=%ld", ulDataLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	BYTE			szMac[512] = {0};
	int				nlen = 512;
	BYTE			*pByte = pbData;
	int				nTemplen = ulDataLen;
	int				SEND_GROUP_LEN = get_max_transmit_len();

	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_mac		*pMac = gm_sc_mgr::get_dev_ptr()->find_mac(hMac, pDev, pApp, pCont);
	if(!pMac)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	if(pbMacData == NULL)
	{
		*pulMacLen = pMac->get_block_size();
		goto END_OF_FUN;
	}


	while(nTemplen > SEND_GROUP_LEN)
	{
		lRslt = app_mac_update(hdev, app_id, cont_id, pMac->mac_id(), pByte, SEND_GROUP_LEN);
		ERROR_THROW_APDU(lRslt);
		
		pByte += SEND_GROUP_LEN;
		nTemplen -= SEND_GROUP_LEN;
	}

	if(nTemplen > 0)
	{
		lRslt = app_mac_update(hdev, app_id, cont_id, pMac->mac_id(), pByte, nTemplen);
		ERROR_THROW_APDU(lRslt)
	}

	lRslt = app_mac_final(hdev, app_id, cont_id, pMac->mac_id(), NULL, 0, szMac, &nlen);
	ERROR_THROW_APDU(lRslt);
	
	TRACE_ASSERT_LEN(*pulMacLen, nlen)

	memcpy(pbMacData, szMac, nlen);
	*pulMacLen = nlen;

END_OF_FUN:
	DBG_LOGMSG("leave SKF_Mac(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_MacUpdate(HANDLE hMac, BYTE * pbData, ULONG ulDataLen)
{
	ULONG lRslt = SAR_OK;
	DBG_LOGMSG("enter SKF_MacUpdate(), ulDataLen=%ld", ulDataLen);
	
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	BYTE			*pByte = pbData;
	int				nTemplen = ulDataLen;
	int				SEND_GROUP_LEN = get_max_transmit_len();
	int				_lastlen = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_mac		*pMac = gm_sc_mgr::get_dev_ptr()->find_mac(hMac, pDev, pApp, pCont);
	if(!pMac)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	while(nTemplen > SEND_GROUP_LEN)
	{
		lRslt = app_mac_update(hdev, app_id, cont_id, pMac->mac_id(), 	pByte, SEND_GROUP_LEN);
		ERROR_THROW_APDU(lRslt);

		pByte += SEND_GROUP_LEN;
		nTemplen -= SEND_GROUP_LEN;
	}

	if(nTemplen > 0)
	{
		lRslt = app_mac_update(hdev, app_id, cont_id, pMac->mac_id(), 	pByte, nTemplen);
		ERROR_THROW_APDU(lRslt);
	}

END_OF_FUN:
	DBG_LOGMSG("leave SKF_MacUpdate(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_MacFinal (HANDLE hMac, BYTE *pbMacData, ULONG *pulMacDataLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_MacFinal(), pulMacDataLen=%ld", pulMacDataLen);
	ULONG			lRslt = SAR_OK;
 	HANDLE			hdev;
	ULONG			app_id, cont_id;
	BYTE			pbData[512] = {0};
	int				nlen = 512;

	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_mac		*pMac = gm_sc_mgr::get_dev_ptr()->find_mac(hMac, pDev, pApp, pCont);
	if(!pMac)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	if(pbMacData == NULL)
	{
		*pulMacDataLen = pMac->get_block_size();
		goto END_OF_FUN;
	}

	lRslt = app_mac_final(hdev, app_id, cont_id, pMac->mac_id(), NULL, 0, pbData, &nlen);
	ERROR_THROW_APDU(lRslt)


	TRACE_ASSERT_LEN(*pulMacDataLen, nlen)
	memcpy(pbMacData, pbData, nlen);
	*pulMacDataLen = nlen;

END_OF_FUN:
	DBG_LOGMSG("leave SKF_MacFinal(), ret=%08x", lRslt);
	return lRslt;
}
